namespace ConsoleApp1;

public class TypeConvert
{
    public void t1()
    {
        object b = new Base();
        Console.WriteLine(b is Base); // output: True
        Console.WriteLine(b is Derived); // output: False

        object d = new Derived();
        Console.WriteLine(d is Base); // output: True
        Console.WriteLine(d is Derived); // output: True
    }

    //以下示例演示，is 运算符将考虑装箱和取消装箱转换，但不会考虑数值转换：
    public void t2()
    {
        int i = 27;
        Console.WriteLine(i is System.IFormattable); // output: True

        object iBoxed = i;
        Console.WriteLine(iBoxed is int); // output: True
        Console.WriteLine(iBoxed is long); // output: False
    }

    //is 运算符还会对照某个模式测试表达式结果。 下面的示例演示如何使用声明模式来检查表达式的运行时类型：
    public void t3()
    {
        int i = 23;
        object iBoxed = i;
        int? jNullable = 7;
        if (iBoxed is int a && jNullable is int b)
        {
            Console.WriteLine(a + b); // output 30
        }
    }

    //as 运算符将表达式结果显式转换为给定的引用或可以为 null 值的类型。 如果无法进行转换，则 as 运算符返回 null。 与强制转换表达式 不同，as 运算符永远不会引发异常。
    public void t4()
    {
        IEnumerable<int> numbers = new List<int>() { 10, 20, 30 };
        IList<int> indexable = numbers as IList<int>;
        if (indexable != null)
        {
            Console.WriteLine(indexable[0] + indexable[indexable.Count - 1]); // output: 40
        }
    }
}

public class Base
{
}

public class Derived : Base
{
}

public readonly struct Digit
{
    private readonly byte digit;

    public Digit(byte digit)
    {
        if (digit > 9)
        {
            throw new ArgumentOutOfRangeException(nameof(digit), "Digit cannot be greater than nine.");
        }

        this.digit = digit;
    }

    //用户定义类型可以定义从或到另一个类型的自定义隐式或显式转换。 隐式转换无需调用特殊语法，并且可以在各种情况（例如，在赋值和方法调用中）下发生。 预定义的 C# 隐式转换始终成功，且永远不会引发异常。 用户定义隐式转换也应如此。 如果自定义转换可能会引发异常或丢失信息，请将其定义为显式转换。
    // is 和 as 运算符不考虑使用用户定义转换。 强制转换表达式用于调用用户定义显式转换。
    // operator 和 implicit 或 explicit 关键字分别用于定义隐式转换或显式转换。 定义转换的类型必须是该转换的源类型或目标类型。 可用两种类型中的任何一种类型来定义两种用户定义类型之间的转换。
    public static implicit operator byte(Digit d) => d.digit;
    public static explicit operator Digit(byte b) => new Digit(b);

    //字符串插值
    //在C#中，$符号通常用于字符串插值（String Interpolation）。字符串插值是一种方便的字符串构建方式，它允许在字符串中直接嵌入变量或表达式的值。
    // 
    // 在你提供的代码中，
    // 符号与大括号
    // 一起使用，用于将变量的值嵌入到字符串中。例如，如果
    // d
    // i
    // g
    // i
    // t
    // 变量的值为
    // 10
    // ，那么表达式
    // 符号与大括号一起使用，用于将变量的值嵌入到字符串中。例如，如果digit变量的值为10，那么表达式"{digit}" 将会被替换为"10"。
    // 
    // 另外，
    // 符号也用于在正则表达式中取消转义字符的作用，这样可以直接在字符串中使用特殊字符。例如，
    // @
    // "
    // \d
    // "
    // 表示匹配数字，而
    // 符号也用于在正则表达式中取消转义字符的作用，这样可以直接在字符串中使用特殊字符。例如，@"\d"表示匹配数字，而符号可以取消转义，使得写作 @"\d"。
    // 
    // 总的来说，在C#中，$符号在字符串插值中起着非常重要的作用，使得字符串的构建变得更加简洁和直观。
    public override string ToString() => $"{digit}";
}

public static class UserDefinedConversions
{
    public static void t1()
    {
        var d = new Digit(7);

        byte number = d;
        Console.WriteLine(number); // output: 7

        Digit digit = (Digit)number;
        Console.WriteLine(digit); // output: 7
    }
}